package com.iflytek.cosmo.ocr.common.json;

import java.text.SimpleDateFormat;
import java.util.Locale;
import java.util.TimeZone;

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * 单例模式获取ObjectMapper对象(ObjectMapper对象线程安全)
 * 
 * @author ljhan2
 */
public abstract class ObjcetMapperBean {

	/**
	 * <code>objectMapper</code>原生单例ObjectMapper对象
	 */
	private static final ObjectMapper originalObjectMapper = new ObjectMapper();

	/**
	 * <code>objectMapper</code>本地化单例ObjectMapper对象
	 */
	private static final ObjectMapper nativeObjectMapper = new ObjectMapper();

	static {
		initNative(nativeObjectMapper);
	}

	/**
	 * 本地初始化ObjectMapper对象
	 * 
	 * @param mapper objectMapper对象
	 * @author ljhan2
	 */
	public static void initNative(ObjectMapper mapper) {
		// 消除语言环境敏感
		// 区域固定中国
		nativeObjectMapper.setLocale(Locale.CHINA);
		// 设置时区（东八区）
		nativeObjectMapper.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));

		// 设置日期格式化，精确到毫秒
		nativeObjectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS"));

		// 设置序列化
		nativeObjectMapper.setSerializationInclusion(Include.ALWAYS);

		// 该特性决定parser将是否允许解析使用Java/C++ 样式的注释（包括'/'+'*' 和'//' 变量）。
		// 由于JSON标准说明书上面没有提到注释是否是合法的组成，所以这是一个非标准的特性；尽管如此，这个特性还是被广泛地使用。注意：该属性默认是false，因此必须显式允许，即通过JsonParser.Feature.ALLOW_COMMENTS
		// 配置为true。
		nativeObjectMapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);

		// 这个特性决定parser是否将允许使用非双引号属性名字，
		// （这种形式在Javascript中被允许，但是JSON标准说明书中没有）。注意：由于JSON标准上需要为属性名称使用双引号，所以这也是一个非标准特性，默认是false的。同样，需要设置JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES为true，打开该特性。
		nativeObjectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);

		// 该特性决定parser是否允许单引号来包住属性名称和字符串值。注意：默认下，该属性也是关闭的。需要设置JsonParser.Feature.ALLOW_SINGLE_QUOTES为true
		nativeObjectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);

		// 该特性决定parser是否允许JSON字符串包含非引号控制字符（值小于32的ASCII字符，包含制表符和换行符）。
		// 如果该属性关闭，则如果遇到这些字符，则会抛出异常。JSON标准说明书要求所有控制符必须使用引号，因此这是一个非标准的特性。注意：默认时候，该属性关闭的。需要设置：
		nativeObjectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);

		// 该特性可以允许接受所有引号引起来的字符，使用‘反斜杠\’机制：如果不允许，只有JSON标准说明书中
		// 列出来的字符可以被避开约束。由于JSON标准说明中要求为所有控制字符使用引号，这是一个非标准的特性，所以默认是关闭的。注意：一般在设置ALLOW_SINGLE_QUOTES属性时，也设置了ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER属性，所以，有时候，你会看到不设置ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER为true，但是依然可以正常运行。
		nativeObjectMapper.configure(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, true);

		nativeObjectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
	}

	/**
	 * 以单例模式获取原生objectMapper对象
	 * 
	 * @return objectMapper对象
	 * @author ljhan2
	 */
	public static ObjectMapper singletonOriginalInstance() {
		return originalObjectMapper;
	}

	/**
	 * 以单例模式获取本地化objectMapper对象
	 * 
	 * @return objectMapper对象
	 * @author ljhan2
	 */
	public static ObjectMapper singletonNativeInstance() {
		return nativeObjectMapper;
	}

	/**
	 * 以多例模式获取objectMapper对象
	 * 
	 * @return objectMapper对象
	 * @author ljhan2
	 */
	public static ObjectMapper prototypeInstance() {
		return new ObjectMapper();
	}

}
